package net.sk.china.front.strategy;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import net.sk.china.common.exception.TalkException;
import net.sk.china.common.model.user.User;
import net.sk.china.common.utils.DateUtil;
import net.sk.china.common.utils.RedisUtil;
import net.sk.china.common.utils.TalkUtil;
import net.sk.china.front.constants.Constants;
import net.sk.china.front.constants.RegularConstants;
import net.sk.china.front.request.LoginRequest;
import net.sk.china.front.request.RegisterRequest;
import net.sk.china.front.response.LoginResponse;
import net.sk.china.front.service.user.UserService;
import net.sk.china.front.token.TokenComponent;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.concurrent.TimeUnit;

/**
 * +----------------------------------------------------------------------
 * // | Talk To [ 聊来改善地区金融服务环境，助力企业发展 ]
 * // +----------------------------------------------------------------------
 * // | Copyright (c) 2018-2024 聊来 All rights reserved.
 * // +----------------------------------------------------------------------
 * // | Licensed ( <a href="http://www.apache.org/licenses/LICENSE-2.0">apache</a> )
 * // +----------------------------------------------------------------------
 * // | @Author: 聊来 <18970881148@qq.com>
 * // +----------------------------------------------------------------------
 * // | DateTime: 2024/6/4 15:10
 * // +----------------------------------------------------------------------
 */
@Component
public class AccountService implements UserInterface {

    private static final Logger logger = LoggerFactory.getLogger(AccountService.class);

    private final UserService userService;

    private final SmsService smsService;

    private final RedissonClient redissonClient;

    private final RedisUtil redisUtil;

    private final TokenComponent tokenComponent;

    public AccountService(UserService userService, SmsService smsService, RedissonClient redissonClient, RedisUtil redisUtil, TokenComponent tokenComponent) {
        this.userService = userService;
        this.smsService = smsService;
        this.redissonClient = redissonClient;
        this.redisUtil = redisUtil;
        this.tokenComponent = tokenComponent;
    }

    /**
     * 账号密码登录
     * @param request 请求对象
     * @param ip 客户端IP
     * @return {@code LoginResponse}
     */
    @Override
    public LoginResponse login(LoginRequest request, String ip) {
        if (StrUtil.isBlank(request.getAccount())) {
            throw new TalkException("账号不能为空");
        }
        if (StrUtil.isBlank(request.getPassword())) {
            throw new TalkException("密码不能为空");
        }
        if (!ReUtil.isMatch(RegularConstants.PASSWORD, request.getPassword())) {
            throw new TalkException("密码格式错误，密码必须以字母开头，长度在6~18之间，只能包含字符、数字和下划线");
        }
        User user = userService.getByAccount(request.getAccount());

        if (ObjectUtil.isNull(user)) {
            throw new TalkException("此账号未注册");
        }
        if (user.getStatus().equals(Constants.NUM_ZERO)) {
            throw new TalkException("当前账户已禁用，请联系平台客服人员！");
        }

        // 校验密码
        String password = TalkUtil.encryptPassword(request.getPassword(), request.getAccount());
        if (!user.getPwd().equals(password)) {
            throw new TalkException("密码错误");
        }

        LoginResponse loginResponse = new LoginResponse();
        try {
            // 生成token
            String token = userService.createToken(user.getUid());
            loginResponse.setToken(token);
        } catch (Exception e) {
            logger.error(String.format("生成用户Token失败: %s", e.getMessage()));
        }

        loginResponse.setType("login");

        // 更新用户登录信息
        UpdateWrapper<User> query = new UpdateWrapper<>();
        query.set("last_ip", ip).set("last_login_time", DateUtil.getNowTime()).set("login_type", request.getLoginType());
        query.eq("uid", user.getUid());
        userService.update(query);

        return loginResponse;
    }


    /**
     * 手机号注册
     * @param request 请求对象
     * @param ip 客户端对象
     * @return {@code LoginResponse}
     */
    public LoginResponse register(RegisterRequest request, String ip) {
        LoginResponse loginResponse = new LoginResponse();

        if (!ReUtil.isMatch(RegularConstants.USER_LOGIN_TYPE, request.getLoginType())) {
            throw new TalkException("用户注册类型不存在");
        }

        if (!request.getPassword().equals(request.getCheckPassword())) {
            throw new TalkException("两次输入的密码不一致");
        }

        RLock lock = redissonClient.getLock("userRegister");

        try {
            boolean isLock = lock.tryLock(10, TimeUnit.SECONDS);
            if (!isLock) {
                throw new TalkException("获取锁失败，无法完成注册操作");
            }

            smsService.checkValidateCode(request.getPhone(), "register", request.getCaptcha());
            User data = userService.getByAccount(request.getPhone());
            if (ObjectUtil.isNotNull(data)) {
                throw new TalkException("您已注册，请勿重新注册");
            }


            LocalDateTime time = DateUtil.getNowTime();

            User user = new User();
            user.setAccount(request.getPhone());
            user.setPwd(TalkUtil.encryptPassword(request.getPassword(), request.getPhone()));
            user.setPhone(request.getPhone());
            user.setUserType(request.getLoginType());
            user.setLoginType(request.getLoginType());
            user.setNickname("");
            user.setAvatar(userService.getAvatar());
            user.setCreateTime(time);
            user.setLastLoginTime(time);
            user.setLastIp(ip);
            user.setAddIp(ip);

            if (!userService.save(user)) {
                throw new TalkException("用户注册失败");
            }

            redisUtil.delete(Constants.SMS_VALIDATE_PHONE + "register" + ":" +  request.getPhone());
            loginResponse.setType("register");
            loginResponse.setToken(userService.createToken(user.getUid()));

        } catch (Throwable e) {
            throw new TalkException(String.format("注册异常：%s", e.getMessage()));
        } finally {
            // 释放锁
            lock.unlock();
        }
        return loginResponse;
    }

    /**
     * 退出登录
     * @param request 请求数据
     */
    public void loginOut(HttpServletRequest request) { tokenComponent.logout(request); }
}
